package server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.text.DecimalFormat;
import java.util.Iterator;

import org.apache.mina.common.IoAcceptor;
import org.apache.mina.transport.socket.nio.SocketAcceptor;
import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;

import server.event.EventManager;
import server.model.npcs.NPCHandler;
import server.model.npcs.NPCDrops;
import server.model.players.PlayerHandler;
import server.model.players.Player;
import server.model.players.Client;
import server.model.players.PlayerSave;
import server.model.minigames.*;
import server.model.npcs.*;
import server.net.ConnectionHandler;
import server.net.ConnectionThrottleFilter;
import server.task.Task;
import server.util.ShutDownHook;
import server.util.SimpleTimer;
import server.util.log.Logger;
import server.world.ItemHandler;
import server.world.ObjectHandler;
import server.world.ObjectManager;
import server.world.ShopHandler;
import server.world.map.VirtualWorld;
import server.world.ClanChatHandler;
import server.world.WorldMap;

/**
 * Server.java
 *
 * @author Sanity
 * @author Graham
 * @author Blake
 * @author Ryan Lmctruck30
 *
 */

public class Server implements Runnable {
	
	
	public static boolean sleeping;
	public static final int cycleRate = 600;
	public static boolean UpdateServer = false;
	public static long lastMassSave = System.currentTimeMillis();
	private static IoAcceptor acceptor;
	private static ConnectionHandler connectionHandler;
	private static ConnectionThrottleFilter throttleFilter;
	private static SimpleTimer engineTimer, debugTimer;
	private static long cycleTime, cycles, totalCycleTime, sleepTime;
	private static DecimalFormat debugPercentFormat;
	public static boolean shutdownServer = false;		
	public static boolean shutdownClientHandler;			
	public static int serverlistenerPort; 
	public static ItemHandler itemHandler = new ItemHandler();
	public static PlayerHandler playerHandler = new PlayerHandler();
    public static NPCHandler npcHandler = new NPCHandler();
	public static ShopHandler shopHandler = new ShopHandler();
	public static ObjectHandler objectHandler = new ObjectHandler();
	public static ObjectManager objectManager = new ObjectManager();
	public static CastleWars castleWars = new CastleWars();
	public static FightPits fightPits = new FightPits();
	public static PestControl pestControl = new PestControl();
	public static NPCDrops npcDrops = new NPCDrops();
	public static ClanChatHandler clanChat = new ClanChatHandler();
	public static FightCaves fightCaves = new FightCaves();
	//public static WorldMap worldMap = new WorldMap();
	//private static final WorkerThread engine = new WorkerThread();
	
	public static Server server;
	
	public static void main(String argv[]) {
		server = new Server();
		new Thread(server).run();
	}
	
	@Override
	public void run() {
		Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
		if(!Config.SERVER_DEBUG) {
			serverlistenerPort = 43594;
		} else {
			serverlistenerPort = 43594;
		}
		shutdownServer = false;
		try {
			
			World.getWorld();
			
			try {
				new RS2Server().start();
			} catch(Exception ex) {
				System.out.println("Error starting the server...");
				ex.printStackTrace();
				System.exit(1);
			}
		 
		System.setOut(new Logger(System.out));
		System.setErr(new Logger(System.err));
		System.out.println("Launching ExtinctionRSPS...");
		
		/**
		 * Server Successfully Loaded 
		 */
		System.out.println("Server listening on port localhost:" + serverlistenerPort);
		/**
		 * Cycle
		 */
		
		while(true) {
			long start = System.nanoTime() / 1000000L;
			World.getWorld().submit(new Task() {
				@Override
				public void execute(GameEngine context) {
					Server.playerHandler.process();			
				}
			});
			World.getWorld().submit(new Task() {
				@Override
				public void execute(GameEngine context) {
					Server.npcHandler.process();
				}
			});
			World.getWorld().submit(new Task() {
				@Override
				public void execute(GameEngine context) {						
					Server.shopHandler.process();
				}
			});
			World.getWorld().submit(new Task() {
				@Override
				public void execute(GameEngine context) {
					Server.objectManager.process();
				}
			});
			World.getWorld().submit(new Task() {
				@Override
				public void execute(GameEngine context) {
					Server.itemHandler.process();
				}
			});
			long sleepTime = 600-(System.nanoTime() / 1000000L - start);
			if (sleepTime > 0) {
				Thread.sleep(sleepTime);
			} else {
				// The server has reached maximum load, players may now lag.
				System.out.println("[WARNING]: Server load: " + (100 + (Math.abs(sleepTime) / (Config.CYCLE_TIME / 100))) + "%!");
			}
		}		
	} catch (Exception e) {
		e.printStackTrace();
	}		
}
	
	public static boolean playerExecuted = false;
	
	public static long getSleepTimer() {
		return sleepTime;
	}
	
	public static void shutDown() {
		acceptor = null;
		connectionHandler = null;
		System.exit(0);
	}
	
	public static void setupLoginChannels() {
		/**
		 * Accepting Connections
		 */
		acceptor = new SocketAcceptor();
		connectionHandler = new ConnectionHandler();
		
		SocketAcceptorConfig sac = new SocketAcceptorConfig();
		sac.getSessionConfig().setTcpNoDelay(false);
		sac.setReuseAddress(true);
		sac.setBacklog(100);
		
		throttleFilter = new ConnectionThrottleFilter(Config.CONNECTION_DELAY);
		sac.getFilterChain().addFirst("throttleFilter", throttleFilter);
		try {
			acceptor.bind(new InetSocketAddress(serverlistenerPort), connectionHandler, sac);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}
